#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;

namespace bit {
    class string {
        friend ostream& operator<<(ostream& _cout, const bit::string& s);
        friend istream& operator>>(istream& _cin, bit::string& s);

    public:
        typedef char* iterator;

    public:
        string(const char* str = "") {
            _size = strlen(str);
            _capacity = _size;
            _str = new char[_capacity + 1];
            strcpy(_str, str);
        }

        string(const string& s) {
            _size = s._size;
            _capacity = s._capacity;
            _str = new char[_capacity + 1];
            strcpy(_str, s._str);
        }

        string& operator=(const string& s) {
            if (this != &s) {
                delete[] _str;
                _size = s._size;
                _capacity = s._capacity;
                _str = new char[_capacity + 1];
                strcpy(_str, s._str);
            }
            return *this;
        }

        ~string() {
            delete[] _str;
        }

        iterator begin() {
            return _str;
        }

        iterator end() {
            return _str + _size;
        }

        void push_back(char c) {
            if (_size == _capacity) {
                reserve(2 * _capacity);
            }
            _str[_size] = c;
            _size++;
            _str[_size] = '\0';
        }

        string& operator+=(char c) {
            push_back(c);
            return *this;
        }

        void append(const char* str) {
            size_t len = strlen(str);
            if (_size + len > _capacity) {
                reserve(_size + len);
            }
            strcpy(_str + _size, str);
            _size += len;
        }

        string& operator+=(const char* str) {
            append(str);
            return *this;
        }

        void clear() {
            delete[] _str;
            _size = 0;
            _capacity = 0;
            _str = new char[_capacity + 1];
            _str[_size] = '\0';
        }

        void swap(string& s) {
            std::swap(_str, s._str);
            std::swap(_size, s._size);
            std::swap(_capacity, s._capacity);
        }

        const char* c_str() const {
            return _str;
        }

        size_t size() const {
            return _size;
        }

        size_t capacity() const {
            return _capacity;
        }

        bool empty() const {
            return _size == 0;
        }

        void resize(size_t n, char c = '\0') {
            if (n > _size) {
                if (n > _capacity) {
                    reserve(n);
                }
                for (size_t i = _size; i < n; ++i) {
                    _str[i] = c;
                }
            }
            _size = n;
            _str[_size] = '\0';
        }

        void reserve(size_t n) {
            if (n > _capacity) {
                char* newStr = new char[n + 1];
                strncpy(newStr, _str, _size);
                delete[] _str;
                _str = newStr;
                _capacity = n;
            }
        }

        char& operator[](size_t index) {
            return _str[index];
        }

        const char& operator[](size_t index) const {
            return _str[index];
        }

        bool operator<(const string& s) {
            return strcmp(_str, s._str) < 0;
        }

        bool operator<=(const string& s) {
            return strcmp(_str, s._str) <= 0;
        }

        bool operator>(const string& s) {
            return strcmp(_str, s._str) > 0;
        }

        bool operator>=(const string& s) {
            return strcmp(_str, s._str) >= 0;
        }

        bool operator==(const string& s) {
            return strcmp(_str, s._str) == 0;
        }

        bool operator!=(const string& s) {
            return strcmp(_str, s._str) != 0;
        }

        size_t find(char c, size_t pos = 0) const {
            if (pos >= _size) {
                return npos;
            }
            const char* found = strchr(_str + pos, c);
            if (found == nullptr) {
                return npos;
            }
            return found - _str;
        }

        size_t find(const char* s, size_t pos = 0) const {
            if (pos >= _size) {
                return npos;
            }
            const char* found = strstr(_str + pos, s);
            if (found == nullptr) {
                return npos;
            }
            return found - _str;
        }

        string& insert(size_t pos, char c) {
            if (pos > _size) {
                pos = _size;
            }
            if (_size == _capacity) {
                reserve(2 * _capacity);
            }
            for (size_t i = _size; i > pos; --i) {
                _str[i] = _str[i - 1];
            }
            _str[pos] = c;
            ++_size;
            _str[_size] = '\0';
            return *this;
        }

        string& insert(size_t pos, const char* str) {
            if (pos > _size) {
                pos = _size;
            }
            size_t len = strlen(str);
            if (_size + len > _capacity) {
                reserve(_size + len);
            }
            for (size_t i = _size; i > pos; --i) {
                _str[i + len - 1] = _str[i - 1];
            }
            strncpy(_str + pos, str, len);
            _size += len;
            _str[_size] = '\0';
            return *this;
        }

        string& erase(size_t pos, size_t len) {
            if (pos >= _size) {
                return *this;
            }
            if (pos + len >= _size) {
                _size = pos;
                _str[_size] = '\0';
                return *this;
            }
            for (size_t i = pos; i + len <= _size; ++i) {
                _str[i] = _str[i + len];
            }
            _size -= len;
            _str[_size] = '\0';
            return *this;
        }

    private:
        char* _str;
        size_t _capacity;
        size_t _size;
        static const size_t npos = -1;
    };

    ostream& operator<<(ostream& _cout, const bit::string& s) {
        _cout << s._str;
        return _cout;
    }

    istream& operator>>(istream& _cin, bit::string& s) {
        _cin >> s._str;
        s._size = strlen(s._str);
        s._capacity = s._size;
        return _cin;
    }
}

int main() {
    bit::string s1("Hello");
    bit::string s2 = "World";
    bit::string s3 = s1;

    cout << "s1: " << s1 << endl;
    cout << "s2: " << s2 << endl;
    cout << "s3: " << s3 << endl;

    s3 = s2;
    s3 += '!';
    cout << "s3: " << s3 << endl;

    s3.append(" Goodbye");
    cout << "s3: " << s3 << endl;

    cout << "s3 size: " << s3.size() << endl;
    cout << "s3 capacity: " << s3.capacity() << endl;

    s3.clear();
    cout << "s3: " << s3 << endl;
    cout << "s3 is empty: " << (s3.empty() ? "true" : "false") << endl;

    s1.swap(s2);
    cout << "s1: " << s1 << endl;
    cout << "s2: " << s2 << endl;

    cout << "s2[0]: " << s2[0] << endl;

    s3 = "Hello World!";
    cout << "s3: " << s3 << endl;
    cout << "Find 'World' in s3: " << s3.find("World") << endl;
    cout << "Inserting 'beautiful ' at index 5: " << s3.insert(5, " beautiful") << endl;

    s3.erase(5, 10);
    cout << "Erasing from index 5 to 15: " << s3 << endl;

    return 0;
}